using System;
using System.Collections.Generic;
using UnityEngine;

namespace Gj
{
    public interface Ai : Control, Cast, Life, Move
    {
        void ExecuteCommand(int commandIndex, Life life);
        AiCommand GetCommand(int commandIndex);
        void RefreshCommand();
    }

    public static class AI_KEY
    {
        public const byte MODEL_LIST = 0;
        public const byte COMMAND_LIST = 0;
        public const byte SCAN_RADIUS = 1;
        public const byte PARTNER_RADIUS = 2;
        public const byte ATTACK_RADIUS = 3;

        public const byte BEHAVIOR_LIST = 4;
//        public const byte SCAN_FREQUENCY = 1;
//        public const byte DECISION_FREQUENCY = 3;
//        public const byte REFRESH_FREQUENCY = 4;
    }

    public enum AI_COMMAND_ATTR : byte
    {
        COMMAND,
        RELATION,
        FLAG,
        PREREQUISITES
    }

    public enum AI_BEHAVIOR_ATTR : byte
    {
        BEHAVIOR,
        STATUS,
        PREREQUISITES
    }

    public enum AI_PREREQUISITE_ATTR : byte
    {
        TYPE,
        TARGET,
        SELECT,
        FILTER,
        VALUE,
        NUMBER,
        SORT
    }

    [Serializable]
    public class AiSoul
    {
        public List<AiModel> models;

        private AiModelKey modelKey = AiModelKey.Standby;

        public AiSoul(object[] objects)
        {
            models = new List<AiModel>();
            foreach (var model in (object[])objects[AI_KEY.MODEL_LIST]) models.Add(new AiModel((object[])model));
        }

        public AiModel model => models[(int)modelKey];

        public void ChangeModel(AiModelKey aiModelKey)
        {
            modelKey = aiModelKey;
        }

        public void Destroy()
        {
//            var e = models.GetEnumerator();
//            while (e.MoveNext())
//            {
//                e.Current.Destroy();
//            }
//            e.Dispose();
        }

        public object[] ToObject()
        {
            var _list = new object[models.Count];

            for (var i = 0; i < _list.Length; i++) _list[i] = models[i].ToObject();

            return new object[] { _list };
        }
    }

    [Serializable]
    public class AiModel
    {
        public int scanRadius;
        public int partnerRadius;

        public int attackRadius;

//        public int scanFrequency;
//        public int refreshFrequency;
//        public int decisionFrequency;
        public List<AiCommand> commands;
        public List<AiBehavior> behaviors;

        public AiModel(object[] objects)
        {
            scanRadius = Convert.ToInt32(objects[AI_KEY.SCAN_RADIUS]);
            partnerRadius = Convert.ToInt32(objects[AI_KEY.PARTNER_RADIUS]);
            attackRadius = Convert.ToInt32(objects[AI_KEY.ATTACK_RADIUS]);
//            scanFrequency = Convert.ToInt32(objects[AI_KEY.SCAN_FREQUENCY]);
//            decisionFrequency = Convert.ToInt32(objects[AI_KEY.DECISION_FREQUENCY]);
//            refreshFrequency = Convert.ToInt32(objects[AI_KEY.REFRESH_FREQUENCY]);
//            Debug.LogFormat("ai model {0}", scanRadius); // , scanFrequency, decisionFrequency, refreshFrequency
            commands = new List<AiCommand>();
            var index = 0;
            foreach (var command in (object[])objects[AI_KEY.COMMAND_LIST])
            {
                commands.Add(new AiCommand((object[])command, index));
                index += 1;
            }

//            index = 0;
//            behaviors = new List<AiBehavior>();
//            foreach (object behavior in (object[])objects[AI_KEY.COMMAND_LIST])
//            {
//                behaviors.Add(new AiBehavior((object[])behavior, index));
//                index += 1;
//            }
        }

//        public void Destroy()
//        {
//            var e = commands.GetEnumerator();
//            while (e.MoveNext())
//            {
//                e.Current.Destroy();
//            }
//            e.Dispose();
//        }
        public object[] ToObject()
        {
            var _list = new object[commands.Count];

            for (var i = 0; i < _list.Length; i++) _list[i] = commands[i].ToObject();

            return new object[] { _list, scanRadius }; // , scanFrequency, decisionFrequency, refreshFrequency
        }
    }

    [Serializable]
    public class AiCommand
    {
        public int command;
        public int relationId;
        public int flag;

        [HideInInspector] public int index;
        [HideInInspector] public float time;
        [HideInInspector] public bool executing;
        [HideInInspector] public bool isError;
        public List<AiPrerequisiteList> prerequisites;

        public AiCommand(object[] objects, int index)
        {
            this.index = index;
            command = Convert.ToInt32(objects[(byte)AI_COMMAND_ATTR.COMMAND]);
            relationId = Convert.ToInt32(objects[(byte)AI_COMMAND_ATTR.RELATION]);
            flag = Convert.ToInt32(objects[(byte)AI_COMMAND_ATTR.FLAG]);
            Debug.LogFormat("ai command {0} {1} {2}", command, relationId, flag);
            var po = (object[])objects[(byte)AI_COMMAND_ATTR.PREREQUISITES];
            prerequisites = new List<AiPrerequisiteList>(po.Length);
            for (var i = 0; i < po.Length; i++) prerequisites.Add(new AiPrerequisiteList((object[])po[i]));
            time = 0;
            executing = false;
            isError = false;
        }

//        public void Destroy()
//        {
//            var e = prerequisites.GetEnumerator();
//            while (e.MoveNext())
//            {
//                e.Current.Destroy();
//            }
//            e.Dispose();
//            prerequisites.Dispose();
//        }

        public object[] ToObject()
        {
            var _list = new object[prerequisites.Count];

            for (var i = 0; i < _list.Length; i++) _list[i] = prerequisites[i].ToObject();
            return new object[] { command, relationId, flag, _list };
        }
    }

    [Serializable]
    public class AiBehavior
    {
        public int behavior;
        public bool status;
        public int[] values;

        public List<AiPrerequisiteList> prerequisites;

        public AiBehavior(object[] objects, int index)
        {
            behavior = Convert.ToInt32(objects[(byte)AI_COMMAND_ATTR.COMMAND]);
            status = Convert.ToBoolean(objects[(byte)AI_BEHAVIOR_ATTR.STATUS]);
            var po = (object[])objects[(byte)AI_COMMAND_ATTR.PREREQUISITES];
            prerequisites = new List<AiPrerequisiteList>(po.Length);
            for (var i = 0; i < po.Length; i++) prerequisites.Add(new AiPrerequisiteList((object[])po[i]));
        }

//        public void Destroy()
//        {
//            var e = prerequisites.GetEnumerator();
//            while (e.MoveNext())
//            {
//                e.Current.Destroy();
//            }
//            e.Dispose();
//            prerequisites.Dispose();
//        }

        public object[] ToObject()
        {
            var _list = new object[prerequisites.Count];

            for (var i = 0; i < _list.Length; i++) _list[i] = prerequisites[i].ToObject();
            return new object[] { behavior, status, _list };
        }
    }

    [Serializable]
    public struct AiPrerequisiteList
    {
        public List<AiPrerequisite> prerequisites;

        public AiPrerequisiteList(object[] objects)
        {
            prerequisites = new List<AiPrerequisite>(objects.Length);
            for (var i = 0; i < objects.Length; i++) prerequisites.Add(new AiPrerequisite((object[])objects[i]));
        }

//        public void Destroy()
//        {
//            prerequisites.Dispose();
//        }
        public object[] ToObject()
        {
            var _list = new object[prerequisites.Count];

            for (var i = 0; i < _list.Length; i++) _list[i] = prerequisites[i].ToObject();

            return _list;
        }
    }

    public enum AiPrerequisiteTarget
    {
        TARGET = 0,
        ENEMY = 1,
        PARTNER = 2,
        PREV = 3,
        SELF = 4,
        MASTER = 5
    }

    public enum AiPrerequisiteCompute
    {
        EQUAL = 0,
        GREATER = 1,
        LESS = 2,
        GREATER_EQUAL = 3,
        LESS_EQUAL = 4
    }

    public enum AiPrerequisiteSort
    {
        None = 0,
        Asc = 1,
        Desc = 2
    }

    [Serializable]
    public struct AiPrerequisite
    {
        public int type;
        public AiPrerequisiteTarget target;
        public int select;
        public AiPrerequisiteCompute filter;
        public int value;
        public int number;
        public AiPrerequisiteSort sort;

        public AiPrerequisite(object[] objects)
        {
            type = Convert.ToInt32(objects[(byte)AI_PREREQUISITE_ATTR.TYPE]);
            target = (AiPrerequisiteTarget)Convert.ToInt32(objects[(byte)AI_PREREQUISITE_ATTR.TARGET]);
            select = Convert.ToInt32(objects[(byte)AI_PREREQUISITE_ATTR.SELECT]);
            filter = (AiPrerequisiteCompute)Convert.ToInt32(objects[(byte)AI_PREREQUISITE_ATTR.FILTER]);
            value = Convert.ToInt32(objects[(byte)AI_PREREQUISITE_ATTR.VALUE]);
            number = Convert.ToInt32(objects[(byte)AI_PREREQUISITE_ATTR.NUMBER]);
            sort = (AiPrerequisiteSort)Convert.ToInt32(objects[(byte)AI_PREREQUISITE_ATTR.SORT]);
            Debug.LogFormat("ai prerequisite {0} {1} {2} {3} {4} {5} {6}", type, target, select, filter, value, number,
                sort);
        }

        public object[] ToObject()
        {
            return new object[] { type, target, select, filter, value, number, sort };
        }
    }

    public enum AiModelKey
    {
        Standby = 0,
        Attack = 1,
        Defense = 2,
        Escape = 3
    }
}